package main

import (
	"fmt"
	"gitee.com/libbylg/pkgr/repo"
	"os"
	"strings"
)

var printers = map[string]func(rootLabels []string) int{
	"list": PrintList,
	"tree": PrintTree,
}

type CmdDependentOptions struct {
	Filter  *repo.ModuleLabelFilter
	Printer string
}

// NewCmdDependentOptions
// pkgr depend  	[PATTERN] [--regex] [--plan PLAN-FILE] [--env ENV-NAME] [--tree|--list]
func NewCmdDependentOptions(argv []string) (*CmdDependentOptions, error) {
	if len(argv) < 2 {
		return nil, fmt.Errorf("the required parameter is missing, try -h for help")
	}

	// 初始化默认值
	opt := &CmdDependentOptions{
		Filter:  repo.NewModuleLabelFilter(),
		Printer: "",
	}

	// 读取选项
	for index := 2; index < len(argv); index++ {
		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--regex" {
			opt.Filter.Regex = true
			continue
		}

		// 指定 plan file 场景
		if argv[index] == "--plan" {
			if len(opt.Filter.PlanFile) != 0 {
				return nil, fmt.Errorf("the install plan file has been specified with `%v'", opt.Filter.PlanFile)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanFile = argv[index]
			continue
		}

		// 指定 plan env 场景
		if argv[index] == "--view" {
			if len(opt.Filter.PlanView) != 0 {
				return nil, fmt.Errorf("the plan env has been specified with `%v'", opt.Filter.PlanView)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanView = argv[index]
			continue
		}

		if argv[index] == "--devrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "devrepo"
			continue
		}

		if argv[index] == "--pkgrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "pkgrepo"
			continue
		}

		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--tree" {
			opt.Printer = "tree"
			continue
		}

		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--list" {
			opt.Printer = "list"
			continue
		}

		// 其他不能识别的参数
		if strings.HasPrefix(argv[index], "-") {
			return nil, fmt.Errorf("unsupported option `%v'", argv[index])
		}

		// 识别 PATTERN 参数
		if len(opt.Filter.Pattern) == 0 {
			opt.Filter.Pattern = argv[index]
			continue
		}

		return nil, fmt.Errorf("unsupported option `%v'", argv[index])
	}

	opt.Filter.Tidy("pkgrepo")

	if opt.Printer == "" {
		opt.Printer = "list"
	}

	return opt, nil
}

func CmdDependent(argv []string) int {
	opt, err := NewCmdDependentOptions(argv)
	if err != nil {
		ERROR("Load option for `%v' failed: %v", "dependent", err.Error())
		return 1
	}

	// PKGREPO 必须存在
	if !repo.PathIsDir(repo.PKGREPO) {
		ERROR("The environment variable `$PKGREPO' is missing")
		return 1
	}

	// 找出所有匹配的label
	moduleLabelList, err := repo.SelectModuleLabels(opt.Filter)
	if err != nil {
		ERROR("Filter module failed: %v", err)
		return 1
	}

	// 将label转换成字符串形式
	rootLabels := make([]string, 0, len(moduleLabelList))
	for _, moduleLabel := range moduleLabelList {
		rootLabels = append(rootLabels, moduleLabel.String())
	}

	// 找到printer
	printer, exist := printers[opt.Printer]
	if !exist {
		ERROR("Unsupported printer `%v'", opt.Printer)
		return 1
	}

	// 按照不同的显示方式显示出来
	return printer(rootLabels)
}

func PrintTree(rootLabels []string) int {
	for _, label := range rootLabels {
		rootTree, err := repo.BuildDependencyTree(label)
		if err != nil {
			ERROR("Build dependency tree for `%v' failed: %v", label, err)
			return 1
		}

		showedMap := make(map[string]bool)
		repo.EnumDependencyTree(0, rootTree, func(depth int, tree *repo.DependencyTree) bool {
			// 确定下是否已经现实过了，如果已经显示过了，而且用户指定不现实重复项目，那么不再显示
			_, showed := showedMap[tree.Label]

			// 如果已经显示过了，就使用特殊的后缀
			suffix := " *"
			if !showed {
				suffix = ""
				showedMap[tree.Label] = true
			}

			if depth == 0 {
				fmt.Fprintf(os.Stdout, "%v%v\n", tree.Label, suffix)
			} else {
				prefix := strings.Repeat("    ", depth)
				fmt.Fprintf(os.Stdout, "%v+-- %v%v\n", prefix, tree.Label, suffix)
			}

			// 如果已经显示过了，就不必继续了
			return !showed
		}, nil)
	}

	return 0
}

func PrintList(rootLabels []string) int {
	showedMap := make(map[string]bool)
	for _, label := range rootLabels {
		rootTree, err := repo.BuildDependencyTree(label)
		if err != nil {
			ERROR("Build dependency tree for `%v' failed: %v", label, err)
			return 1
		}
		repo.EnumDependencyTree(0, rootTree, func(depth int, tree *repo.DependencyTree) bool {
			// 确定下是否已经现实过了，如果已经显示过了，而且用户指定不现实重复项目，那么不再显示
			_, showed := showedMap[tree.Label]
			if !showed {
				showedMap[tree.Label] = true
			}
			return !showed
		}, func(depth int, tree *repo.DependencyTree) {
			fmt.Fprintf(os.Stdout, "%v\n", tree.Label)
		})
	}

	return 0
}
